﻿using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Drawing;

namespace BullsEyeGame
{
    internal delegate void SubmitDelegate(GuessLine i_SubmitedGuess);

    /// <summary>
    /// A class that holds the components of a whole line from the game board
    /// including the guess buttons, submit button and result buttons.
    /// </summary>
    internal class GuessLine
    {
        private const bool k_Enabled = true;

        private const int k_SizeOfGuessButtonEdge = 40;
        private const int k_SizeOfGuessButtonPadding = 4;
        
        private const int k_WidthOfSubmitGuessButton = 36;
        private const int k_HeightOfSubmitGuessButton = 16;
        private const string k_TextOfSubmitGuessButton = "-->>";
        private const int k_SizeOfSubmitGuessButtonHorizontalPadding = 4;
        private const int k_SizeOfSubmitGuessButtonVerticalPadding = 4;
        
        private const int k_SizeOfGuessResultButtonEdge = 14;
        private const int k_SizeOfGuessResultButtonHorizontalPadding = 2;
        private const int k_SizeOfGuessResultButtonVerticalPadding = 2;
        private const int k_SizeOfGuessResultPartLeftPadding = 6;

        private static readonly int sr_Height;
        private static readonly Color sr_ControlColor = Color.FromKnownColor(KnownColor.Control);

        private readonly int r_linesVerticalStartingPoint;
        private int m_LineNumber;
        private Button m_ButtonSubmitGuess = new Button();
        private List<Button> m_GuessButtons = new List<Button>();
        private List<Button> m_GuessResultButtons = new List<Button>();

        private event SubmitDelegate m_SubmitDelegate = null;

        static GuessLine()
        {
            int GuessTotalHight, GuessResultTotalHeight, SubmitGuessTotalHeight;

            GuessTotalHight = k_SizeOfGuessButtonEdge + (2 * k_SizeOfGuessButtonPadding);
            GuessResultTotalHeight = (2 * k_SizeOfGuessResultButtonEdge) + (4 * k_SizeOfGuessButtonPadding);
            SubmitGuessTotalHeight = k_HeightOfSubmitGuessButton + (2 * k_SizeOfSubmitGuessButtonVerticalPadding);
            sr_Height = Math.Max(Math.Max(GuessTotalHight, GuessResultTotalHeight), SubmitGuessTotalHeight);
        }

        /// <summary>
        /// A constructor for the GuessLine
        /// </summary>
        /// <param name="i_LineNumber">The line number of this guess line out of all guess lines in board</param>
        /// <param name="i_LinesVerticalStartingPoint">An upper padding for the GuessLines section in the board</param>
        public GuessLine(int i_LineNumber, int i_LinesVerticalStartingPoint)
        {
            m_LineNumber = i_LineNumber;
            r_linesVerticalStartingPoint = i_LinesVerticalStartingPoint;
            createAllComponents();
        }

        /// <summary>
        /// Property to get the Line number of this guess line
        /// </summary>
        public int LineNumber
        {
            get { return m_LineNumber; }
        }

        /// <summary>
        /// Property to get or set the submit delegate of this guess line's submit button
        /// </summary>
        public SubmitDelegate SubmitDelegate
        {
            get { return m_SubmitDelegate; }
            set { m_SubmitDelegate += value; }
        }

        /// <summary>
        /// Property to get the guess result buttons of this guess line
        /// </summary>
        public List<Button> GuessResultButtons
        {
            get { return m_GuessResultButtons; }
        }

        /// <summary>
        /// Property to get all the controls residing in this guess line
        /// </summary>
        public Control[] Controls
        {
            get
            {
                return getAllControls().ToArray();
            }
        }

        /// <summary>
        /// Property to get the chosen colors of this guess line's guess buttons
        /// </summary>
        public List<Color> SelectedColors
        {
            get
            {
                List<Color> result = new List<Color>();
                foreach (Button currentButton in m_GuessButtons)
                {
                    result.Add(currentButton.BackColor);
                }

                return result;
            }
        }

        /// <summary>
        /// Property to get or set the Enabled property of the submit guess button of this guess line
        /// </summary>
        public bool SubmitGuessButtonEnabled
        {
            get
            {
                return m_ButtonSubmitGuess.Enabled;
            }

            set
            {
                m_ButtonSubmitGuess.Enabled = value;
            }
        }

        /// <summary>
        /// Gets an indication whether this guess line is valid for submission 
        /// </summary>
        /// <returns>The indication whether this guess line is valid for submission</returns>
        public bool IsValidGuessLine()
        {
            return isAllGuessColorSelected();
        }

        /// <summary>
        /// Disables all the guess buttons of this guess line
        /// </summary>
        public void DisableGuessButtons()
        {
            foreach (Button guessButton in m_GuessButtons)
	        {
                guessButton.Enabled = !k_Enabled;
	        }
        }

        private List<Control> getAllControls()
        {
            List<Control> allControls = new List<Control>(m_GuessButtons.Count + m_GuessResultButtons.Count + 1);

            allControls.AddRange(m_GuessButtons.ToArray());
            allControls.Add(m_ButtonSubmitGuess);
            allControls.AddRange(m_GuessResultButtons.ToArray());

            return allControls;
        }

        private void createAllComponents()
        {
            createAllGuessButtons();
            createSubmitButton();
            createAllGuessResultButtons();
        }

        private void createAllGuessButtons()
        {
            Button currentGuessSubUnitButton;
            int left, top;

            for (int i = 0; i < Guess.GuessLength; ++i)
            {
                currentGuessSubUnitButton = new Button();
                currentGuessSubUnitButton.Size = new Size(k_SizeOfGuessButtonEdge, k_SizeOfGuessButtonEdge);
                left = (i * (k_SizeOfGuessButtonPadding + k_SizeOfGuessButtonEdge)) + k_SizeOfGuessButtonPadding;
                top = k_SizeOfGuessButtonPadding + (m_LineNumber * sr_Height) + r_linesVerticalStartingPoint;
                currentGuessSubUnitButton.Location = new Point(left, top);
                currentGuessSubUnitButton.Click += guessSubUnitButton_Click;
                m_GuessButtons.Add(currentGuessSubUnitButton);
            }
        }

        private void createSubmitButton()
        {
            int left, top;

            m_ButtonSubmitGuess.Size = new Size(k_WidthOfSubmitGuessButton, k_HeightOfSubmitGuessButton);
            m_ButtonSubmitGuess.Text = k_TextOfSubmitGuessButton;
            left = m_GuessButtons[m_GuessButtons.Count - 1].Right + k_SizeOfSubmitGuessButtonHorizontalPadding;
            top = (sr_Height / 2) - (k_HeightOfSubmitGuessButton / 2) + (m_LineNumber * sr_Height) + r_linesVerticalStartingPoint;
            m_ButtonSubmitGuess.Location = new Point(left, top);
            m_ButtonSubmitGuess.Click += m_ButtonSubmitGuess_Click;
        }

        private void createAllGuessResultButtons()
        {
            int numOfResultsInFirstRow, numOfResultsInSecondRow, leftOfGuessResultPart;
            int center, firstRowTop, secondRowTop;

            numOfResultsInFirstRow = Guess.GuessLength / 2;
            numOfResultsInSecondRow = Guess.GuessLength - numOfResultsInFirstRow;
            leftOfGuessResultPart = m_ButtonSubmitGuess.Right + k_SizeOfGuessResultPartLeftPadding;
            center = (m_ButtonSubmitGuess.Top + m_ButtonSubmitGuess.Bottom) / 2;
            firstRowTop = center - (k_SizeOfGuessResultButtonEdge + k_SizeOfGuessResultButtonVerticalPadding);
            secondRowTop = center + k_SizeOfGuessResultButtonVerticalPadding;
            initializeRowOfGuessResultButtons(firstRowTop, leftOfGuessResultPart, numOfResultsInFirstRow);
            initializeRowOfGuessResultButtons(secondRowTop, leftOfGuessResultPart, numOfResultsInSecondRow);
        }

        private void initializeRowOfGuessResultButtons(int i_Top, int i_LeftStartingPoint, int i_NumberOfButtonsToAdd)
        {
            Button currentGuessResultSubUnitButton;

            for (int i = 0; i < i_NumberOfButtonsToAdd; ++i)
            {
                currentGuessResultSubUnitButton = createSingleButtonFromRowOfGuessResult(i, i_LeftStartingPoint, i_Top);
                m_GuessResultButtons.Add(currentGuessResultSubUnitButton);
            }
        }

        private Button createSingleButtonFromRowOfGuessResult(int i_ButtonIndex, int i_LeftStartingPoint, int i_Top)
        {
            int left;
            Button guessResultSubUnitButton;

            guessResultSubUnitButton = new Button();
            guessResultSubUnitButton.Size = new Size(k_SizeOfGuessResultButtonEdge, k_SizeOfGuessResultButtonEdge);
            left = (i_ButtonIndex * (k_SizeOfGuessResultButtonHorizontalPadding + k_SizeOfGuessResultButtonEdge)) + k_SizeOfGuessResultButtonHorizontalPadding;
            left += i_LeftStartingPoint;
            guessResultSubUnitButton.Location = new Point(left, i_Top);
            guessResultSubUnitButton.Enabled = !k_Enabled;

            return guessResultSubUnitButton;
        }

        private void guessSubUnitButton_Click(object sender, EventArgs e)
        {            
            Button buttonGuessSubUnitClicked = (Button)sender;
            FormColorBoard formColorBoard = new FormColorBoard();
            DialogResult dialogResult = formColorBoard.ShowDialog();

            if (dialogResult == DialogResult.OK)
            {
                buttonGuessSubUnitClicked.BackColor = formColorBoard.LastChosenColor;
            }
        }
        
        private void m_ButtonSubmitGuess_Click(object sender, EventArgs e)
        {
            if (m_SubmitDelegate != null)
            {
                SubmitDelegate(this);
            }
        }
        
        private bool isAllGuessColorSelected()
        {
            bool result = true;
            List<Color> guessColorsList = SelectedColors;
            if (guessColorsList.Count != Guess.GuessLength)
            {
                result = false;
            }
            else
            {
                foreach (Color currentGuessColor in guessColorsList)
                {
                    if (currentGuessColor == sr_ControlColor)
                    {
                        result = false;
                        break;
                    }
                }
            }

            return result;
        }        
    }
}
